package org.dromara.sheet.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import org.dromara.common.core.service.DictService;
import org.dromara.common.core.service.SheetService;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.generator.constant.GenConstants;
import org.dromara.generator.domain.GenTableColumn;
import org.dromara.generator.mapper.GenTableColumnMapper;
import org.dromara.generator.util.GenUtils;
import org.dromara.sheet.constant.SplitType;
import org.dromara.sheet.domain.SysDataSource;
import org.dromara.sheet.domain.SysSheetField;
import org.dromara.sheet.domain.SysSheetSource;
import org.dromara.sheet.enums.YesOrNoEnum;
import org.dromara.sheet.mapper.SysDataSourceMapper;
import org.dromara.sheet.mapper.SysSheetFieldMapper;
import org.dromara.sheet.mapper.SysSheetMapper;
import org.dromara.sheet.mapper.SysSheetSourceMapper;
import org.dromara.sheet.service.ISysSheetService;
import org.springframework.stereotype.Service;
import org.dromara.sheet.domain.bo.SysSheetBo;
import org.dromara.sheet.domain.vo.SysSheetVo;
import org.dromara.sheet.domain.SysSheet;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;


/**
 * 应用Service业务层处理
 *
 * @author Ysl
 * @date 2023-07-26
 */
@RequiredArgsConstructor
@Service
public class SysSheetServiceImpl implements ISysSheetService, SheetService {

    private final SysSheetMapper baseMapper;
    private final SysSheetFieldMapper sheetFieldMapper;
    private final GenTableColumnMapper genTableColumnMapper;
    private final SysSheetSourceMapper sheetSourceMapper;
    private final SysDataSourceMapper dataSourceMapper;

    /**
     * 查询应用
     */
    @Override
    public SysSheetVo queryById(Long sheetId){
        return baseMapper.selectVoById(sheetId);
    }

    /**
     * 查询应用列表
     */
    @Override
    public TableDataInfo<SysSheetVo> queryPageList(SysSheetBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<SysSheet> lqw = buildQueryWrapper(bo);
        Page<SysSheetVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询应用列表
     */
    @Override
    public List<SysSheetVo> queryList(SysSheetBo bo) {
        LambdaQueryWrapper<SysSheet> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<SysSheet> buildQueryWrapper(SysSheetBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<SysSheet> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getPid() != null, SysSheet::getPid, bo.getPid());
        lqw.like(StringUtils.isNotBlank(bo.getName()), SysSheet::getName, bo.getName());
        lqw.like(StringUtils.isNotBlank(bo.getTitleName()), SysSheet::getTitleName, bo.getTitleName());
        lqw.like(StringUtils.isNotBlank(bo.getShortName()), SysSheet::getShortName, bo.getShortName());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysSheet::getStatus, bo.getStatus());
        lqw.eq(StringUtils.isNotBlank(bo.getTableId()), SysSheet::getTableId, bo.getTableId());
        lqw.eq(bo.getLeftFixedIndex() != null, SysSheet::getLeftFixedIndex, bo.getLeftFixedIndex());
        lqw.eq(bo.getRightFixedIndex() != null, SysSheet::getRightFixedIndex, bo.getRightFixedIndex());
        lqw.eq(StringUtils.isNotBlank(bo.getRemark()), SysSheet::getRemark, bo.getRemark());
        lqw.orderByDesc(SysSheet::getCreateTime);
        return lqw;
    }

    /**
     * 新增应用
     */
    @Override
    public Boolean insertByBo(SysSheetBo bo) {
        SysSheet add = MapstructUtils.convert(bo, SysSheet.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setSheetId(add.getSheetId());

            String dataName = DynamicDataSourceContextHolder.peek();
            List<GenTableColumn> genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(bo.getTableName(), dataName);

            // 保存应用字段
            List<SysSheetField> fieldList = new ArrayList<>();
            AtomicInteger count = new AtomicInteger(1);
            genTableColumns.forEach(column -> {
                String dataType = GenUtils.getDbType(column.getColumnType());
                // 1:String， 2：Integer， 3： Long， 4：BigDecimal， 5：Date
                Integer fieldType = 1;
                Integer showType = 1;
                if (GenUtils.arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || GenUtils.arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType)) {
                    fieldType = 1;
                    // 字符串长度超过500设置为文本域
                    Integer columnLength = GenUtils.getColumnLength(column.getColumnType());
                    showType = columnLength >= 500 || GenUtils.arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? 5 : 1;

                } else if (GenUtils.arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType)) {
                    // 如果是浮点型 统一用BigDecimal
                    String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), StringUtils.SEPARATOR);
                    if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0) {
                        fieldType = 4;
                        showType = 3;
                    }
                    // 如果是整形
                    else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10) {
                        column.setJavaType(GenConstants.TYPE_INTEGER);
                        fieldType = 2;
                        showType = 2;
                    }
                    // 长整形
                    else {
                        fieldType = 3;
                        showType = 2;
                    }
                } else if (GenUtils.arraysContains(GenConstants.COLUMNTYPE_TIME, dataType)) {
                    fieldType = 5;
                    showType = 15;
                }
                int tableSort = count.get() * 10;
                SysSheetField field = new SysSheetField();
                field.setSheetId(add.getSheetId());
                field.setFieldName(column.getColumnName());
                field.setChineseName(column.getColumnComment());
                field.setFieldType(fieldType);
                field.setShowType(showType);
                field.setTableSort(tableSort);
                field.setFormSort(tableSort);
                field.setFormStatus(YesOrNoEnum.YES.getCode());
                field.setTableStatus(YesOrNoEnum.YES.getCode());
                field.setShowForm(YesOrNoEnum.YES.getCode());
                field.setShowTable(YesOrNoEnum.YES.getCode());
                fieldList.add(field);

                count.getAndIncrement();

            });
            sheetFieldMapper.insertBatch(fieldList);

            // 保存数据源
            List<SysSheetSource> sheetSourceList = new ArrayList<>();
            if (StringUtils.isNotBlank(bo.getDictId())){
                Map<Long, String> dictIdMap = SpringUtils.getBean(DictService.class).getAllDictByDictId(bo.getDictId());
                dictIdMap.forEach((key, value) ->{
                    SysSheetSource source = new SysSheetSource();
                    source.setSheetId(add.getSheetId());
                    source.setDataSourceType(1);
                    source.setDataSourceId(key);
                    source.setDataSourceName(value);
                    sheetSourceList.add(source);
                });
            }
            if (StringUtils.isNotBlank(bo.getSourceId())){
                List<SysDataSource> dataSourceList = dataSourceMapper.selectList(
                    new LambdaQueryWrapper<SysDataSource>().in(SysDataSource::getDataSourceId, (Object) bo.getSourceId().split(","))
                );
                for (SysDataSource dataSource : dataSourceList) {
                    SysSheetSource source = new SysSheetSource();
                    source.setSheetId(add.getSheetId());
                    source.setDataSourceType(2);
                    source.setDataSourceId(dataSource.getDataSourceId());
                    source.setDataSourceName(dataSource.getName());
                    source.setCrossField(dataSource.getCrossField());
                    sheetSourceList.add(source);
                }
            }
            sheetSourceMapper.insertBatch(sheetSourceList);
        }
        return flag;
    }

    /**
     * 修改应用
     */
    @Override
    public Boolean updateByBo(SysSheetBo bo) {
        SysSheet update = MapstructUtils.convert(bo, SysSheet.class);
        validEntityBeforeSave(update);
        // 保存数据源
//        sheetSourceMapper.delete(
//            new LambdaQueryWrapper<SysSheetSource>().eq(SysSheetSource::getSheetId, bo.getSheetId())
//        );
        List<SysSheetSource> sourceList = sheetSourceMapper.selectList(
            new LambdaQueryWrapper<SysSheetSource>().eq(SysSheetSource::getSheetId, bo.getSheetId())
        );
        List<SysSheetSource> insertSheetSourceList = new ArrayList<>();
        List<SysSheetSource> updateSheetSourceList = new ArrayList<>();
        if (StringUtils.isNotBlank(bo.getDictId())){
            Map<Long, String> dictIdMap = SpringUtils.getBean(DictService.class).getAllDictByDictId(bo.getDictId());
            dictIdMap.forEach((key, value) ->{
                SysSheetSource sysSheetSource = sourceList.stream().filter(item -> item.getDataSourceType().equals(1) && item.getDataSourceId().equals(key)).findFirst().orElse(null);
                if (sysSheetSource == null){
                    SysSheetSource source = new SysSheetSource();
                    source.setSheetId(bo.getSheetId());
                    source.setDataSourceType(1);
                    source.setDataSourceId(key);
                    source.setDataSourceName(value);
                    insertSheetSourceList.add(source);
                } else {
                    sysSheetSource.setDataSourceName(value);
                    updateSheetSourceList.add(sysSheetSource);
                }

            });
        }
        if (StringUtils.isNotBlank(bo.getSourceId())){
            List<SysDataSource> dataSourceList = dataSourceMapper.selectList(
                new LambdaQueryWrapper<SysDataSource>().in(SysDataSource::getDataSourceId, bo.getSourceId().split(SplitType.SPLIT_COMMA))
            );
            for (SysDataSource dataSource : dataSourceList) {
                SysSheetSource sysSheetSource = sourceList.stream().filter(item -> item.getDataSourceType().equals(2) && item.getDataSourceId().equals(dataSource.getDataSourceId())).findFirst().orElse(null);
                if (sysSheetSource == null){
                    SysSheetSource source = new SysSheetSource();
                    source.setSheetId(bo.getSheetId());
                    source.setDataSourceType(2);
                    source.setDataSourceId(dataSource.getDataSourceId());
                    source.setDataSourceName(dataSource.getName());
                    source.setCrossField(dataSource.getCrossField());
                    insertSheetSourceList.add(source);
                } else {
                    sysSheetSource.setDataSourceId(dataSource.getDataSourceId());
                    sysSheetSource.setDataSourceName(dataSource.getName());
                    sysSheetSource.setCrossField(dataSource.getCrossField());
                    updateSheetSourceList.add(sysSheetSource);
                }

            }
        }

        // 新增
        if (!insertSheetSourceList.isEmpty()){
            sheetSourceMapper.insertBatch(insertSheetSourceList);
        }
        // 修改
        if (!updateSheetSourceList.isEmpty()){
            sheetSourceMapper.updateBatchById(updateSheetSourceList);
        }

        // 删除
        List<Long> noList = sourceList.stream().map(SysSheetSource::getSheetSourceId).filter(sheetSourceId ->
            !updateSheetSourceList.stream().map(SysSheetSource::getSheetSourceId).toList().contains(sheetSourceId)
        ).toList();
        if (!noList.isEmpty()){
            sheetSourceMapper.deleteBatchIds(noList);
        }

        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(SysSheet entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除应用
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 是否存在菜单子节点
     *
     * @param sheetId 菜单ID
     * @return 结果
     */
    @Override
    public boolean hasChildBySheetId(Long sheetId) {
        return baseMapper.exists(new LambdaQueryWrapper<SysSheet>().eq(SysSheet::getPid, sheetId));
    }

    /**
     * 通过应用ID获取应用名称
     * @param sheetId
     * @return
     */
    @Override
    public String selectSheetNameById(Long sheetId) {
        SysSheet sheet = baseMapper.selectOne(new LambdaQueryWrapper<SysSheet>()
            .select(SysSheet::getName).eq(SysSheet::getSheetId, sheetId));
        return ObjectUtil.isNull(sheet) ? null : sheet.getName();
    }
}
